#include <time.h>
#include <winsock2.h>
#include "MySQL/mysql.h"
#include "pThreads/semaphore.h"
#include <vector>
#include "CSemaphore.h"

#include "CZoneHandler.h"
#include "CSpawnPointHandler.h"
#include "CLuaManager.h"
#include "CUtil.h"


#include "CPacket.h"
#include "CDb.h"
#include "CConsole.h"
#include "CSpawnPointGroup.h"
#include "CSpawnMobPool.h"
#include <algorithm>
//using std::random_shuffle;




CSpawnPointGroup::CSpawnPointGroup() {
}

CSpawnPointGroup::~CSpawnPointGroup() {
}

bool CSpawnPointGroup::loadSpawnMobPool() {

	MYSQL* mysqlConn;
	int count;
	char query[4096];

	MYSQL_RES * res;
	MYSQL_ROW row;

	memset(query,0,4096);

	sprintf(query, " SELECT poolid,	respawntime, flags,	maxspawns, dropid, minLevel, maxLevel FROM spawn_grouptopool WHERE groupid = %i", this->m_groupId);

	count = (int) strlen(query);

	mysqlConn=CDb::getConn(); //get conn
	mysql_real_query(mysqlConn, query, count);

	res = mysql_store_result(mysqlConn);
	CDb::pushConn(mysqlConn); //release conn


	if( (res!=NULL) && (mysql_num_rows(res) > 0) )
	{

		while((row = mysql_fetch_row(res)))
		{
			// new spawnpool entry
			CSpawnMobPool * pNewSpawnPool;
			pNewSpawnPool = new CSpawnMobPool();

			// fill general settings
			pNewSpawnPool->m_groupId = this->m_groupId;
			pNewSpawnPool->m_respawnTime = atoi(row[1]);
			pNewSpawnPool->m_flags = atoi(row[2]);
			pNewSpawnPool->m_maxSpawns = atoi(row[3]);
			pNewSpawnPool->m_currentSpawns = 0;
			pNewSpawnPool->m_dropId = atoi(row[4]);
			pNewSpawnPool->m_minLevel = atoi(row[5]);
			pNewSpawnPool->m_maxLevel = atoi(row[6]);

			// link the spawnpool with the right mobpoolentry
			for(unsigned int i = 0; i < CMobHandler::getInstance()->m_mobPool[this->m_zoneId].size(); i++) {
				if( CMobHandler::getInstance()->m_mobPool[this->m_zoneId].at(i)->intid == atoi(row[0]) ) {
					pNewSpawnPool->m_pMobPool = CMobHandler::getInstance()->m_mobPool[this->m_zoneId].at(i);
					break;
				}
			}

			// add the whole thing to the group
			this->m_pSpawnMobPool.push_back(pNewSpawnPool);

		}

	}
	if (res!=NULL)
		mysql_free_result(res);

	if(this->m_pSpawnMobPool.size() > 0)
		return true;
	else
		return false;

}


bool CSpawnPointGroup::loadSpawnPoints() {


	MYSQL* mysqlConn;
	int count;
	char query[4096];

	MYSQL_RES * res;
	MYSQL_ROW row;

	memset(query,0,4096);

	sprintf(query, " SELECT spawnid, groupid, pos_x, pos_y, pos_z, pos_rot FROM spawn_point WHERE groupid = %i", this->m_groupId);

	count = (int) strlen(query);

	mysqlConn=CDb::getConn(); //get conn
	mysql_real_query(mysqlConn, query, count);

	res = mysql_store_result(mysqlConn);
	CDb::pushConn(mysqlConn); //release conn


	if( (res!=NULL) && (mysql_num_rows(res) > 0) )
	{

		while((row = mysql_fetch_row(res)))
		{
		
			SpawnPoint * pSp;
			pSp = new SpawnPoint();

			pSp->m_groupId  = this->m_groupId;
			pSp->m_spawnId	= atoi(row[0]);
			pSp->m_pos.x	= (float)atof(row[2]);
			pSp->m_pos.y	= (float)atof(row[3]);
			pSp->m_pos.z	= (float)atof(row[4]);
			pSp->m_pos.rotation = atoi(row[5]);
			pSp->tod		= 0;
			pSp->m_pMob		= NULL;

			this->m_spawnList.push_back(pSp);


		}

	} else {
		//CConsole::outDebOnly("No spawnpoints found for %s", this->m_pSpawnMobPool.front()->m_pMobPool->name);
	}
	if (res!=NULL)
		mysql_free_result(res);

	if(this->m_spawnList.size() > 0)
		return true;
	else
		return false;


}

void CSpawnPointGroup::checkSpawnPoints() {

	if(this->m_spawnList.size() == 0) {
		return;
	}

	for(unsigned int i = 0; i < this->m_pSpawnMobPool.size(); i++) {
		CSpawnMobPool * pMP = this->m_pSpawnMobPool.at(i);
		for(unsigned int j = 0; j < this->m_spawnList.size(); j++) {
			bool isSpawned = false;
		
			SpawnPoint * pSP = this->m_spawnList.at(j);

			if(pSP->m_pMob != NULL) {
				isSpawned = true;
			}

			
			if(((time(NULL) - pSP->tod) > pMP->m_respawnTime ) && ( pMP->m_currentSpawns < pMP->m_maxSpawns ) && !isSpawned){
				
				mobIDPoolEntry* mIDPE = CMobHandler::getInstance()->getNextMobId(pMP->m_pMobPool,pMP->m_respawnTime,this->m_groupId,pMP->m_maxSpawns);
				if((mIDPE != NULL) && pMP->isSpawnConditionMet())  {
					CConsole::outDebOnly("Spawning %s ",pMP->m_pMobPool->name);
					pSP->tod = 0;
					pSP->m_pParentPool = pMP;
					pMP->m_currentSpawns++;
					CMobHandler::getInstance()->spawn(0, mIDPE, pMP, pSP);
				}
			} else if (isSpawned) {

				// if already spawned, idle ->
				// check spawncondition
				// if needed despawn
				if((!pMP->isSpawnConditionMet()) && (pSP->m_pMob->ownerId == 0) && (pSP->m_pMob->tod == 0) ) {
					pSP->m_pMob->update = false;
					pSP->m_pMob->clearEnmityList();
					pSP->m_pMob->tod = (unsigned long)time(NULL);
					CreateThread(0,0,DespawnNoWait,pSP->m_pMob,0,0);
				}

			}
		}
		std::random_shuffle(this->m_spawnList.begin(),this->m_spawnList.end());
	}





}